// NeuralNetTester.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include "windows.h"

#include "NeuralNetFourLayers.h"
#include "NeuralNetTwoLayers.h"

#include "Layer.h"

#include "PillboxCollider.h"

typedef NeuralNetFourLayers<NnetLayer<2, 6, 1, 1>, NnetLayer<6, 4, 1, 1>, NnetLayer<4, 2, 1,0>, NnetLayer<2,2,0,0> > PolarToCart4LayerTest;

void TestPolarToCart(const char * szFileNameForData, int nTrainingRuns, const char * szAnnOut, const char * szTrueOut);

void TestTwoLayerNet(const char * szFileNameForData, int nTrainingRuns);

void TestPillbox();

int _tmain(int argc, _TCHAR* argv[])
{
	TestPillbox();

	DWORD nStartTime = GetTickCount();
	// TestPolarToCart("C:\\polar_to_cart_c.txt", 100000000, "C:\\ann_out.txt", "C:\\true_function_out.txt");

	TestTwoLayerNet("C:\\two_layer_net.txt", 5000);

	DWORD nEndTime = GetTickCount();

	fprintf(stderr,"Time elapsed is %d milliseconds\n", nEndTime - nStartTime);
	fprintf(stdout,"Time elapsed is %d milliseconds\n", nEndTime - nStartTime);

	
	return 0;
}

void TestPillbox()
{
	PillboxCollider myCollider(10.0, 5.0, 0.0, 0.0, 0.0);

	myCollider.SetAngleStep(0.5);

	myCollider.Move(1, 1.0);
	myCollider.Move(-1, 1.0);
	myCollider.Move(-1, 1.0);
	myCollider.Move(1, 1.0);
}

void TestTwoLayerNet(const char * szFileNameForData, int nTrainingRuns)
{
	NeuralNetTwoLayers<NnetLayer<2, 5, 1, 1>, NnetLayer<5, 1, 1, 1> > netToTrain;

	netToTrain.SetLearnRate(0.5);
	int i;
	double arrLfInput[2];
	double arrLfOutput[1];
	for(i = 0; i < nTrainingRuns; ++i)
	{
		
		arrLfInput[0] = (rand()/((double)RAND_MAX))*2.0-1.0;
		arrLfInput[1] = (rand()/((double)RAND_MAX))*2.0-1.0;
		
		arrLfOutput[0] = 0.0;
		if((arrLfInput[0]*arrLfInput[0] + arrLfInput[1]*arrLfInput[1]) < 0.707)
		{
			arrLfOutput[0] = 1.0;
		}

		arrLfOutput[0] += (rand()/((double)RAND_MAX))*((0.5*nTrainingRuns)/((0.5*nTrainingRuns)+i));
		double lfScratchVar;
		netToTrain.Train(arrLfInput, arrLfOutput, &lfScratchVar);

	}

	FILE * fOut = fopen(szFileNameForData, "w");

	for(int i = 0; i < 100; ++i)
	{
		for(int j = 0; j < 100; ++j)
		{
			arrLfInput[0] = (i/50.0)-1.0;
			arrLfInput[1] = (j/50.0)-1.0;

			arrLfOutput[0] = netToTrain.Eval(arrLfInput)[0];

			fprintf(fOut, "%lf|", arrLfOutput[0]);
			
		}
		fprintf(fOut, "\n");
		fflush(fOut);
	}
	fclose(fOut);
}

void TestPolarToCart(const char * szFileNameForData, int nTrainingRuns, const char * szAnnOut, const char * szTrueOut)
{
	PolarToCart4LayerTest myNnetTest;
	double arrLfPolar[2];
	double arrLfCartesian[2];
	double arrLfScratch[2];

	for(int iTrainRun = 0; iTrainRun < nTrainingRuns; ++iTrainRun)
	{
		arrLfPolar[0] = (rand()/((double)RAND_MAX))*3.141592654;
		arrLfPolar[1] = (rand()/((double)RAND_MAX))+1.0;

		arrLfCartesian[0] = arrLfPolar[1]*cos(arrLfPolar[0]);
		arrLfCartesian[1] = arrLfPolar[1]*sin(arrLfPolar[0]);

		myNnetTest.Train(arrLfPolar, arrLfCartesian, arrLfScratch);
	}

	FILE * fOut = fopen(szFileNameForData, "w");
	// , const char * szAnnOut, const char * szTrueOut
	FILE * fiAnnOut = fopen(szAnnOut, "w");
	FILE * fiTrueOut = fopen(szTrueOut, "w");

	for(int i = 0; i < 100; ++i)
	{
		for(int j = 0; j < 100; ++j)
		{
			arrLfPolar[0] = i*3.141592654*0.01;
			arrLfPolar[1] = j*0.01+1.0;

			arrLfCartesian[0] = arrLfPolar[1]*cos(arrLfPolar[0]);
			arrLfCartesian[1] = arrLfPolar[1]*sin(arrLfPolar[0]);

			const double * const pLfOut = myNnetTest.Eval(arrLfPolar);

			double lfErr = (pLfOut[0]-arrLfCartesian[0])*(pLfOut[0]-arrLfCartesian[0])+
				(pLfOut[1]-arrLfCartesian[1])*(pLfOut[1]-arrLfCartesian[1]);

			fprintf(fOut, "%lf|", lfErr);
			fprintf(fiAnnOut, "%lf|", pLfOut[0]);
			fprintf(fiTrueOut, "%lf|", arrLfCartesian[0]);
			
		}
		fprintf(fOut, "\n");
		fprintf(fiAnnOut,"\n");
		fprintf(fiTrueOut, "\n");
		fflush(fOut);
		fflush(fiAnnOut);
		fflush(fiTrueOut);
	}
	fclose(fOut);
	fclose(fiAnnOut);
	fclose(fiTrueOut);
}

